package com.open.source.excel.importto;

import com.open.source.excel.model.BaseImportModel;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;

/**
 * @author ZhangLong on 2019/10/16  5:56 下午
 * @version V1.0
 */
public class ImportExcelData {

    public ImportExcelData() {
        this.sheetsData = new ConcurrentHashMap<>();
    }

    /**
     * description sheet的数据
     */
    private final Map<Integer, SheetData> sheetsData;

    /**
     * description 获取全部sheet数据列表
     */
    public Map<Integer, SheetData> getAll() {
        return sheetsData;
    }

    /**
     * description 根据sheet页获取数据
     */
    public List<? extends BaseImportModel> getDataBySheetNum(int sheetNum) {
        final SheetData sheetData = sheetsData.get(sheetNum);
        return Optional.ofNullable(sheetData).map(SheetData::getData).orElseGet(ArrayList::new);
    }

    /**
     * description 根据sheet页获取
     */
    public List<? extends BaseImportModel> getErrorDataBySheetNum(int sheetNum) {
        final SheetData sheetData = sheetsData.get(sheetNum);
        return Optional.ofNullable(sheetData).filter(SheetData::hasError)
                .map(SheetData::getErrorData).orElseGet(ArrayList::new);
    }

    /**
     * description 获取多个sheet错误信息列表
     */
    public Map<Integer, SheetData> errorSheetsData() {
        final Map<Integer, SheetData> errorDataMap = new HashMap<>();
        sheetsData.forEach((sheetNo, sheetData) -> {
            if (sheetData.hasError()) {
                errorDataMap.put(sheetNo, sheetData);
            }
        });
        return errorDataMap;
    }

    public boolean hasError() {
        return !errorSheetsData().isEmpty();
    }

    /**
     * description 添加model到指定sheet
     */
    public void dataAdd(int sheetNum, BaseImportModel model) {

        if (sheetsData.containsKey(sheetNum)) {
            sheetsData.get(sheetNum).getData().add(model);
        } else {
            SheetData sheetData = new SheetData();
            sheetData.getData().add(model);
            sheetsData.put(sheetNum, sheetData);
        }
    }

    /**
     * create by ZhangLong on 2019/10/16 description 不要数据data/errorData循环中直接使用调用该方法,循环中进行remove可能会导致
     * {@link ConcurrentModificationException}
     */
    public <M extends BaseImportModel> void errorModelAdd(int sheetNum, M model) {
        SheetData sheetData = sheetsData.get(sheetNum);
        sheetData.getData().remove(model);
        sheetData.getErrorData().add(model);
    }

    /**
     * description 初始化sheet数据
     */
    public void initSheetData(Integer sheetNo) {
        sheetsData.put(sheetNo, new SheetData());
    }

    @Data
    public static class SheetData {

        private List<BaseImportModel> data;
        private List<BaseImportModel> errorData;
        private Class<BaseImportModel> mClass;

        SheetData() {
            data = new ArrayList<>();
            errorData = new ArrayList<>();
        }

        /**
         * description 当前sheet是否存在错误信息
         */
        public boolean hasError() {
            return CollectionUtils.isNotEmpty(errorData);
        }
    }
}
